/*******************************************************************************
 * Copyright (c) 2011 TXT e-solutions SpA
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the research area ICT-2009.1.3
 * Internet of Things and enterprise environments.
 *
 *
 * Authors:
 *     Cristoforo Seccia (TXT e-solutions SpA)
 *
 * Contributors:
 *      Domenico Rotondi (TXT e-solutions SpA)
 *******************************************************************************/
package it.txt.access.capability.demo.server.tcp;

import it.txt.access.capability.commons.signer.model.X509CertificateKeyValues;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Cristoforo Seccia (TXT e-solutions SpA)
 */
public class ResponseServer implements Runnable {

    private static final Logger LOGGER = Logger.getLogger(ResponseServer.class.getName());
    private ResponseClientSupport progressSupport;
    private ServerSocket serverSocket = null;
    protected boolean isListening = false;
    protected int port;

    public ResponseServer(int serverPort, X509CertificateKeyValues keyValues) {
        port = serverPort;
        progressSupport = new ResponseClientSupport(keyValues);
    }

    public ResponseServer(int serverPort, X509CertificateKeyValues keyValues,
            PropertyChangeListener source) {
        this(serverPort, keyValues);
        progressSupport.addPropertyChangeListener(source);
    }

    public synchronized boolean isListening() {
        return isListening;
    }

    private void startListening() {
        try {
            //Creating a new server socket
            serverSocket = new ServerSocket(port);
            //recupero info su server
            InetAddress info = serverSocket.getInetAddress();
            String infoAdreess = info.getHostAddress();
            int infoPort = serverSocket.getLocalPort();
            LOGGER.log(Level.INFO, "Server Started with Name: {0} and Port: {1}",
                    new Object[]{infoAdreess, infoPort});
            //Fire new event ready to accept request ok
            fireRequestReadySuccessEvent();
            //Return success
            isListening = true;
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
            //Fire new event ready to accept request ok
            fireStartingRequestReadyErrorEvent();
        }
    }

    public synchronized void stopListening() {
        try {
            isListening = false;
            //close the server socket
            if (serverSocket != null) {
                LOGGER.log(Level.INFO, "Closing server socket...");
                serverSocket.close();
            }
            LOGGER.log(Level.INFO, "Server socket closed.");

        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, e.getMessage(), e);
        }
        //Fire new event ready to accept request reset
        fireRequestReadySettingsEvent();
    }

    public void run() {
        //Start the server by open the server socket
        startListening();
        //While the socket is listening
        while (isListening()) {
            Socket clientSocket = null;
            try {
                //Accept new client connection
                LOGGER.log(Level.INFO, "Waiting for a client...");
                clientSocket = serverSocket.accept();
                LOGGER.log(Level.INFO, "Client connection accepted from: {0}",
                        clientSocket.getInetAddress().toString());
            } catch (IOException e) {
                if (!isListening()) {
                    LOGGER.log(Level.INFO, "Server Stopped while accepting.");
                    return;
                }
                //Accepting error
                LOGGER.log(Level.SEVERE, e.getMessage(), e);
                //Fire new event connection enstablished error.
                fireConnectionWithClientErrorEvent();
            }
            //Start a new client consumer thread
            new Thread(new ResponseClient(clientSocket, progressSupport),
                    "Capability_Worker_Thread").start();
        }
        LOGGER.log(Level.INFO, "Server Thread Stopped.");
    }

    private void fireRequestReadySuccessEvent() {
        //Fire new event ready to accept request starting ok.
        progressSupport.fireCapabilityServerEvent(
                ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_READY,
                ResponseClientSupport.STATE_SETTINGS,
                ResponseClientSupport.STATE_OK);
    }

    private void fireRequestReadySettingsEvent() {
        //Fire new event ready to accept request reset.
        progressSupport.fireCapabilityServerEvent(
                ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_READY,
                ResponseClientSupport.STATE_OK,
                ResponseClientSupport.STATE_SETTINGS);
    }

    private void fireStartingRequestReadyErrorEvent() {
        //Fire new event ready to accept request starting error.
        progressSupport.fireCapabilityServerEvent(
                ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_READY,
                ResponseClientSupport.STATE_SETTINGS,
                ResponseClientSupport.STATE_ERROR);
    }

    private void fireConnectionWithClientErrorEvent() {
        //Fire new event connection enstablished error.
        progressSupport.fireCapabilityServerEvent(
                ResponseClientSupport.EVENT_NAME_TCP_CONNECTION,
                ResponseClientSupport.STATE_SETTINGS,
                ResponseClientSupport.STATE_ERROR);
    }
}
